package com.falcon.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.falcon.core.enums.ResponseCodeEnum;
import com.falcon.core.utils.AssertUtil;
import com.falcon.core.utils.BeanUtils;
import com.falcon.domain.dos.RoleDO;
import com.falcon.domain.dos.UserDO;
import com.falcon.domain.po.RolePO;
import com.falcon.domain.po.UserPO;
import com.falcon.domain.po.UserRolePO;
import com.falcon.domain.req.UserQuery;
import com.falcon.domain.req.UserRequest;
import com.falcon.mapper.IRoleMapper;
import com.falcon.mapper.IUserMapper;
import com.falcon.mapper.IUserRoleMapper;
import com.falcon.mvc.domain.BasePager;
import com.falcon.service.IRoleService;
import com.falcon.service.IUserService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.swan.mybatis.condition.Condition;
import com.swan.mybatis.condition.OpType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;


@Slf4j
@Service
public class UserService implements IUserService {

    @Autowired
    private IUserMapper userMapper;

    @Autowired
    private IRoleMapper roleMapper;

    @Autowired
    private IUserRoleMapper userRoleMapper;

    @Autowired
    private IRoleService roleService;

    @Transactional
    @Override
    public Long save(UserRequest request){

        this.validateRoleId(request.getRoleIds());

        UserPO userPO = BeanUtil.copyProperties(request, UserPO.class);

        // 保存主表
        this.userMapper.insertNotNull(userPO);

        // 保存关系表
        this.saveUserRole(userPO.getId(), request.getRoleIds());

        return userPO.getId();
    }

    @Transactional
    @Override
    public Boolean update(Long id, UserRequest request){

        this.validateRoleId(request.getRoleIds());

        // 更新主表
        UserPO userPO = BeanUtil.copyProperties(request, UserPO.class);
        userPO.setId(id);
        boolean success = this.userMapper.updateNotNull(userPO);

        // 处理关系表:先删后增
        this.userRoleMapper.deleteList(Condition.newInstance().and(UserRolePO.Fields.userId, OpType.equals, id));
        this.saveUserRole(id, request.getRoleIds());

        return success;
    }

    @Override
    public Boolean deleteById(Long id) {

        return this.userMapper.deleteById(id);
    }

    @Override
    public UserDO queryById(Long id){

        // 查询用户详情
        UserPO userPO = this.userMapper.selectById(id);
        UserDO userDO = BeanUtil.copyProperties(userPO, UserDO.class);

        // 查询角色列表
        List<RolePO> rolePOS = this.roleService.queryRoleListByUserId(id);
        userDO.setRoles(BeanUtils.copyToList(rolePOS, RoleDO.class));
        return userDO;
    }


    @Override
    public List<UserDO> queryList(UserQuery request){

        Condition condition = request.toCondition();

        List<UserPO> poList = this.userMapper.selectList(condition);

        List<UserDO> doList = BeanUtil.copyToList(poList, UserDO.class);

        return doList;
    }

    @Override
    public BasePager<UserDO> queryPager(UserQuery request){


        PageInfo<UserPO> pageInfo = PageHelper.startPage(request.getPage(), request.getPageSize())
                .doSelectPageInfo(() -> this.userMapper.selectList(request.toCondition()));

        return BeanUtils.toPager(pageInfo, UserDO.class);
    }

    @Override
    public int batchDelete(List<Long> ids) {

        return this.userMapper.deleteByIds(ids);
    }

    private List<RolePO> validateRoleId(List<Long> roleIds) {
        // 查询角色列表
        List<RolePO> rolePOS = this.roleMapper.selectListByIds(roleIds);

        // 校验参数
        Set<Long> findIds = rolePOS.stream().map(RolePO::getId).collect(Collectors.toSet());
        Long notExtId = roleIds.stream().filter(roleId -> !findIds.contains(roleId)).findAny().orElse(null);
        AssertUtil.assertTrue(Objects.isNull(notExtId), ResponseCodeEnum.PAGE_TIMEOUT);

        return rolePOS;
    }

    private void saveUserRole(Long userId, List<Long> roleIds) {
        roleIds.stream()
                .map(roleId -> new UserRolePO().setUserId(userId).setRoleId(roleId))
                .forEach(this.userRoleMapper::insertNotNull);
    }

}

